package com.pi.dc.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import com.alibaba.fastjson.JSON;
import com.pi.base.dto.result.respcode.smart.DcResp;
import com.pi.base.enumerate.record.RecordState;
import com.pi.base.enumerate.redis.RedisCacheEnum;
import com.pi.base.exception.ServiceException;
import com.pi.base.util.cache.RedisUtil;
import com.pi.base.util.time.DateTools;
import com.pi.comm.sequence.SnowflakeFactory;
import com.pi.dc.dao.entity.DcBedNatureEntity;
import com.pi.dc.dao.entity.DcDeviceInfoEntity;
import com.pi.dc.dao.mapper.DcBedNatureMapper;
import com.pi.dc.enumerate.DcDevTypeEnum;
import com.pi.dc.facade.UserBedFacade;
import com.pi.dc.model.DcBedStatusPostForm;
import com.pi.dc.smart.SmartConstants;
import com.pi.dc.vo.UserBedInfoVo;
import com.pi.dc.vo.UserBedSketch;

@Validated
@Service
public class DcBedService {
  private static final Logger logger = LoggerFactory.getLogger(DcBedService.class);
  @Autowired
  private UserBedFacade userBedFacade;
  @Autowired
  private DcBedNatureMapper bedNatureMapper;
  @Autowired
  private DcDeviceInfoService deviceInfoService;
  
  private static final Pattern WIFI_PATTERN = Pattern.compile("^[\\w\\-\\.]+$");
  private static final String DEFAULT_WIFISSID = "hstc";
  private static final String DEFAULT_WIFIPASS = "88888888";
  
  public Long addBedInfo(
      @NotBlank(message="DC_DEVICE.DEVICE_CODE_EMPTY")
      @Length(min = 1, max = 40, message="DC_DEVICE.DEVICE_CODE_LENGTH_ILLGAL")     
      String deviceCode,
      @NotNull
      @Min(value = 1, message="REQ_COMMON.SOURCE_ID_EMPTY")
      Long sourceId,
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND")
      Long ownerId){
    DcDeviceInfoEntity exist = deviceInfoService.getByDevCodeIfExist(deviceCode, DcDevTypeEnum.SMART_BED.getType());
//    if(null != exist && exist.getDeviceState() != RecordState.STATE_DELETE.getCode()
//        && form.getOwnerId().longValue() != exist.getOwnerId()){
//      throw new ServiceException(DcResp.RESP_DEVICE_WAS_REGISTERED);
//    }
    if(null == exist){
      return addBaseDevInfo(deviceCode, ownerId, sourceId);
    }else{
      if(sourceId != exist.getSourceId().longValue()) {
        throw new ServiceException("DC_DEV.DEV_IS_BINDED");
      }
      if(ownerId.longValue() != exist.getOwnerId()) {
        exist.setDevName(generateDefaultName(deviceCode));
        //其他人注册需要注销设备信息
        resetBedNature(exist.getId());
      }
      exist.setOwnerId(ownerId);
      exist.setState(RecordState.STATE_NORMAL.getCode());
      deviceInfoService.updateBaseDevInfo(exist);
      return exist.getId();
    }
  }

  public void addBedWifi(
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND") Long operateUserId, 
      @NotNull(message="DC_DEVICE.DEVICE_ID_EMPTY")Long devId, 
      @NotBlank(message = "DC_DEVICE.WIFI_SSID_EMPTY")String wifiSsid, 
      @NotBlank(message = "DC_DEVICE.WIFI_PASS_EMPTY")String wifiPass) {
    verifyWifi(wifiSsid, wifiPass);
    //检查用户是否有此设备权限
    DcDeviceInfoEntity devInfo = deviceInfoService.getById(devId);
    if(null == devInfo || devInfo.getState() != RecordState.STATE_NORMAL.getCode()){
      throw new ServiceException("DC_DEV.DEV_INFO_EMPTY");
    }
    if(devInfo.getOwnerId() != operateUserId.longValue()){
      throw new ServiceException(DcResp.RESP_PRIVILEGE_NOT_FOUND);
    }
    String[] wifiArr = new String[2];
    wifiArr[0] = wifiSsid;
    wifiArr[1] = wifiPass;
    RedisUtil.directset(
        RedisCacheEnum.SMART_DEVICE_WIFI, JSON.toJSONString(wifiArr), 
        new Object[]{devInfo.getDevCode()});
    updateBedWifiNatureById(devId, wifiSsid, wifiPass, 1);
  }
  
  private void verifyWifi(String wifiSsid, String wifiPass) {
    if(StringUtils.isBlank(wifiSsid) || StringUtils.isBlank(wifiPass) 
        || wifiSsid.length()>16 || wifiPass.length() >16 
        || !WIFI_PATTERN.matcher(wifiSsid).find() || !WIFI_PATTERN.matcher(wifiPass).find()) {
      throw new ServiceException("SMART_WIFI.WIFI_IS_MALFORMED");
    }
  }

  public UserBedSketch queryUserBedVo(
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND") Long ownerId){
    List<UserBedInfoVo> bedList = queryUserBedInfoVo(ownerId);
    return queryUserBedSketch(bedList, ownerId);
  }
  
  /**
   * @description 查询用户分享, 如果带shareId, 则查询分享人的信息
   * @param userId 用户编号
   * @param shareId 分享编号
   * @return
   */
  public UserBedSketch queryUserBedVoWithShare(
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND") Long userId,
      Long shareId){
    List<DcDeviceInfoEntity> devInfoList = deviceInfoService.queryUserBedListByShare(userId, shareId);
    return queryUserBedSketch(queryUserBedInfoVo(devInfoList), CollectionUtils.isEmpty(devInfoList)? 0L: devInfoList.get(0).getOwnerId());
  }
  
  private Long countAllBedUser(long actualUserCount) {
    return 30 * (DateTools.getDateInterval(SmartConstants.START_CAL_DATE, new Date())) + 2510 + actualUserCount;
  }
  
  private UserBedSketch queryUserBedSketch(List<UserBedInfoVo> bedList, long ownerId) {
    Long userCount = deviceInfoService.countAllDevice();
    userCount = countAllBedUser(userCount);
    return userBedFacade.translateToUserBedSketch(bedList, userCount, ownerId);
  }
  
  public DcBedNatureEntity getOrCreateBedNature(
      @NotBlank(message="DC_DEVICE.DEVICE_CODE_EMPTY")
      @Length(min = 1, max = 40, message="DC_DEVICE.DEVICE_CODE_LENGTH_ILLGAL")
      String devCode){
    DcDeviceInfoEntity devInfo = deviceInfoService.getByDevCode(devCode, DcDevTypeEnum.SMART_BED.getType());
    if(null == devInfo) {
      logger.info("设备信息不存在： {}", devCode);
      return null;
    }
    return getOrCreateBedNature(devInfo.getId());
  }
  
  public DcBedNatureEntity getOrCreateBedNature(@NotNull(message="DC_DEVICE.DEVICE_ID_EMPTY") Long devId){
    DcBedNatureEntity nature = bedNatureMapper.findOne(devId);
    if(null != nature) {
      return nature;
    }else {
      DcBedNatureEntity entity = new DcBedNatureEntity();
      entity.setId(devId);
      entity.setBatteryStatus(0);
      entity.setLatestActiveTime(0L);
      entity.setRelativeHumidity(0);
      entity.setState(RecordState.STATE_NORMAL.getCode());
      entity.setTemperature(0);
      entity.setWifiSsid(StringUtils.EMPTY);
      entity.setWifiPass(StringUtils.EMPTY);
      entity.setWifiStatus(0);
      entity.setVersion(200L);
      bedNatureMapper.insert(entity);
      return entity;
    }
  }
  
  private Long addBaseDevInfo(String devCode, Long ownerId, Long sourceId) {
    DcDeviceInfoEntity baseInfoEntity = new DcDeviceInfoEntity();
    baseInfoEntity.setDevCode(devCode);
    baseInfoEntity.setDevName(generateDefaultName(devCode));
    baseInfoEntity.setDevType(DcDevTypeEnum.SMART_BED.getType());
    baseInfoEntity.setOwnerId(ownerId);
    baseInfoEntity.setSourceId(sourceId);
    baseInfoEntity.setId(SnowflakeFactory.getDefaultWorker().nextId());
    deviceInfoService.add(baseInfoEntity);
    return baseInfoEntity.getId();
  }
  
  private String generateDefaultName(String devCode) {
    return "小眠贝" + devCode.substring(devCode.length() -5);
  }
  /**
   * @description 根据用户和被子编号查询可能的被子列表
   * @param ownerId
   * @param bedId 可选，被子编号
   * @return
   */
  public List<UserBedInfoVo> queryUserBedInfoVo(
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND") Long ownerId){
    List<DcDeviceInfoEntity> deviceInfoList = deviceInfoService.queryUserDevInfo(ownerId);
    return queryUserBedInfoVo(deviceInfoList);
  }
  
  private List<UserBedInfoVo> queryUserBedInfoVo(List<DcDeviceInfoEntity> devInfoList){
    if(CollectionUtils.isEmpty(devInfoList)) {
      return new ArrayList<>(0);
    }
    List<Long> ids = new ArrayList<>(devInfoList.size());
    for(DcDeviceInfoEntity entity:devInfoList) {
      ids.add(entity.getId());
    }
    List<DcBedNatureEntity> natures = bedNatureMapper.getByIds(ids);
    return userBedFacade.transLateBedEntitiesToVO(devInfoList, natures);
  }
  
  public void updateDeviceBattery(DcBedStatusPostForm form) {
    DcDeviceInfoEntity devInfo = deviceInfoService.getByDevCodeIfExist(form.getDeviceCode(), DcDevTypeEnum.SMART_BED.getType());
    if(null == devInfo) {
      logger.info("设备{}未注册", form.getDeviceCode());
      return;
    }
    DcBedNatureEntity nature = getOrCreateBedNature(devInfo.getId());
    nature.setBatteryStatus(form.getBatteryStatus());
    nature.setTemperature(form.getTemperature());
    nature.setRelativeHumidity(form.getRelativeHumidity());
    nature.setLatestActiveTime(System.currentTimeMillis());
    bedNatureMapper.updateById(nature);
  }

  /**
   * @description 重置被子的基础属性(不包括wifi)
   * @param bedId
   */
  public void resetBedNature( @NotNull(message="DC_DEV.DEV_ID_EMPTY") Long bedId) {
    DcBedNatureEntity entity = bedNatureMapper.findOne(bedId);
    if(null ==  entity || entity.getState() == RecordState.STATE_DELETE.getCode()) {
      return;
    }
    DcBedNatureEntity bedNature = new DcBedNatureEntity();
    bedNature.setState(RecordState.STATE_NORMAL.getCode());
    bedNature.setId(bedId);
    bedNature.setVersion(entity.getVersion());
    bedNatureMapper.updateById(bedNature);
  }
  
  /**
   * @description 重置被子相关信息(包括属性和wifi)
   * @param bedId
   * @param operateUserId
   */
  public void resetBedInfo( @NotNull(message="DC_DEV.DEV_ID_EMPTY") Long bedId, 
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND") Long operateUserId) {
    resetBedNature(bedId);
    //下发被子的wifi重置指令
    addBedWifi(operateUserId, bedId, DEFAULT_WIFISSID, DEFAULT_WIFIPASS);
  }
  
  public void delBedInfo( @NotNull(message="DC_DEV.DEV_ID_EMPTY") Long bedId, 
      @NotNull(message="DC_DEVICE.DEVICE_USER_NOT_FOUND") Long operateUserId) {
    DcDeviceInfoEntity deviceInfo = deviceInfoService.getById(bedId);
    if(null == deviceInfo){
      throw new ServiceException("DC_DEV.DEV_INFO_EMPTY");
    }
//    if(null ==  entity || null == entity.getLatestActiveTime() || (System.currentTimeMillis() - entity.getLatestActiveTime()) > 60000 ) {
//      throw  new ServiceException("DC_DEV.DEV_IS_OFFLINE");
//    }
    resetBedInfo(bedId, operateUserId);
    deviceInfoService.delDeviceInfo(bedId, operateUserId);
  }
  
  public void updateBedWifiNatureById(@NotNull(message="DC_DEV.DEV_ID_EMPTY") Long devId,
      String wifiSsid, String wifiPass, @NotNull(message="SMART_WIFI.WIFI_STATUS_EMPTY")Integer status){
    DcBedNatureEntity entity = getOrCreateBedNature(devId);
    entity.setWifiStatus(status);
    entity.setWifiSsid(wifiSsid);
    entity.setWifiPass(wifiPass);
    bedNatureMapper.updateById(entity);
  }
  
  /**
   * wifi 配置成功后设置在线状态和配置状态
   * @param devCode 设备编号
   * @param status 状态
   */
  public void activeBedWifi(@NotNull(message="DC_DEV.DEV_ID_EMPTY") String devCode,
      @NotNull(message="SMART_WIFI.WIFI_STATUS_EMPTY")Integer status){
    DcBedNatureEntity entity = getOrCreateBedNature(devCode);
    entity.setWifiStatus(status);
    entity.setLatestActiveTime(System.currentTimeMillis());
    bedNatureMapper.updateById(entity);
  }
}
